class Solution {
    /*
    我们不妨以示例一中的字符串 \texttt{abcabcbb}abcabcbb 为例，找出从每一个字符开始的，不包含重复字符的最长子串，
    那么其中最长的那个字符串即为答案。对于示例一中的字符串，我们列举出这些结果，其中括号中表示选中的字符以及最长的字符串：

    以 \texttt{(a)bcabcbb}(a)bcabcbb 开始的最长字符串为 \texttt{(abc)abcbb}(abc)abcbb；
    以 \texttt{a(b)cabcbb}a(b)cabcbb 开始的最长字符串为 \texttt{a(bca)bcbb}a(bca)bcbb；
    以 \texttt{ab(c)abcbb}ab(c)abcbb 开始的最长字符串为 \texttt{ab(cab)cbb}ab(cab)cbb；
    以 \texttt{abc(a)bcbb}abc(a)bcbb 开始的最长字符串为 \texttt{abc(abc)bb}abc(abc)bb；
    以 \texttt{abca(b)cbb}abca(b)cbb 开始的最长字符串为 \texttt{abca(bc)bb}abca(bc)bb；
    以 \texttt{abcab(c)bb}abcab(c)bb 开始的最长字符串为 \texttt{abcab(cb)b}abcab(cb)b；
    以 \texttt{abcabc(b)b}abcabc(b)b 开始的最长字符串为 \texttt{abcabc(b)b}abcabc(b)b；
    以 \texttt{abcabcb(b)}abcabcb(b) 开始的最长字符串为 \texttt{abcabcb(b)}abcabcb(b)。
    
发现了什么？如果我们依次递增地枚举子串的起始位置，那么子串的结束位置也是递增的！
这里的原因在于，假设我们选择字符串中的第 k 个字符作为起始位置，并且得到了不包含重复字符的最长子串的结束位置为 r_k。
那么当我们选择第 k+1 个字符作为起始位置时，首先从 k+1 到 r_k的字符显然是不重复的，并且由于少了原本的第 k个字符，
我们可以尝试继续增大 r_k，直到右侧出现了重复字符为止。
*/
    public int lengthOfLongestSubstring(String s) {
        int left = 0,right = 0;
        int len = s.length()-1;
        int res = 0;              // 可能为空字符串
        int[] bok = new int[200]; // 初始化记录数组
        while( right<=len ){
            int ch = (int)s.charAt(right);
            bok[ch] ++;
            // 窗口左移
            while( bok[ch]>1 ){
                bok[ (int)s.charAt(left) ] --;
                left++;
            }
            // [left,right]这个区间维护了最长的无重复字串
            res = Math.max(res,right-left+1);
            // 窗口右移
            right ++;
        }
        return res;
    }
}